package com.avladov.components
{
	import mx.core.mx_internal;
	
	import spark.components.Scroller;
	import spark.effects.ThrowEffect;
	import spark.effects.animation.Keyframe;
	import spark.effects.animation.MotionPath;
	
	use namespace mx_internal;
	
	/**
	 * Scroller modification by avladov.com. July 1, 2012
	 * For documentation and help visit http://avladov.com
	 * 
	 * Extends Flex 4.5 spark scroller component and allows you to disable scrolling overshootting (pull/bounce)
	 * beyond viewport dimension when interactionMode is TOUCH.
	 *  
	 * @author Angel Vladov
	 * @version 1.0
	 */
	public class Scroller extends spark.components.Scroller
	{
		private var m_overshootEnabled:Boolean = true;
		
		/**
		 * If you set this to false then the scroller won't bounce the content beyound its boundaries.
		 */
		[Inspectable(defaultValue="true", category="General")]
		public function get overhsootEnabled():Boolean {
			return m_overshootEnabled;
		}

		public function set overhsootEnabled(value:Boolean):void {
			m_overshootEnabled = value;
		}

		override mx_internal function performThrow(velocityX:Number, velocityY:Number):void {
			super.performThrow(velocityX, velocityY);
			
			if (!overhsootEnabled && throwEffect.isPlaying) {
				var mpaths:Vector.<MotionPath> = throwEffect.motionPaths;
				var changed:Boolean = false;
				
				for (var i:uint = 0; i < mpaths.length; i++) {
					var motion:MotionPath = mpaths[i];
					
					switch (motion.property) {
						case "horizontalScrollPosition":
							if(fixThrowFrames(motion.keyframes, 0, viewport.contentWidth - viewport.width)) {
								changed = true;
							}
							
							break;
						
						case "verticalScrollPosition":
							if(fixThrowFrames(motion.keyframes, 0, viewport.contentHeight - viewport.height)) {
								changed = true;
							}
							
							break;
					}
				}
				
				if(changed) {
					throwEffect.stop();
					throwEffect.play();
				}
			}
		}
		
		override mx_internal function performDrag(dragX:Number, dragY:Number):void {
			super.performDrag(dragX, dragY);
			
			if(!overhsootEnabled) {
				viewport.horizontalScrollPosition = fixScrollValue(viewport.horizontalScrollPosition, 0, viewport.contentWidth - viewport.width);
				viewport.verticalScrollPosition = fixScrollValue(viewport.verticalScrollPosition, 0, viewport.contentHeight - viewport.height);
			}
		}
		
		private function fixScrollValue(currentValue:Number, minValue:Number, maxValue:Number):Number {
			if (currentValue < minValue) {
				return 0;
			}
			else if (currentValue > maxValue) {
				return Math.max(maxValue, minValue);
			}
			
			return currentValue;
		}
		
		private function fixThrowFrames(kframes:Vector.<Keyframe>, minValue:Number, maxValue:Number):Boolean {
			var changed:Boolean = false;
			
			for (var i:uint = 0; i < kframes.length; i++) {
				var frame:Keyframe = kframes[i];
				
				if (frame.value < minValue) {
					frame.value = minValue;
					changed = true;
				}
				else if (frame.value > maxValue) {
					frame.value = Math.max(maxValue, minValue);
					changed = true;
				}
			}
			
			return changed;
		}
	}
}